package org.langcom;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Writer;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.eclipse.core.runtime.FileLocator;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Platform;
import org.osgi.framework.Bundle;

public class CommonProperties {

	private static final String SLASH = "/";
	private static final String COMMENT = "#";
	private static final String NN = "\n";
	private static final String REGEX = "=";
	protected String filePath;
	private Map<String, String> propertyMap = new HashMap<String, String>();
	private List<CProperty> propertyList = new ArrayList<CommonProperties.CProperty>();
	private boolean isLoaded = false;
	private RequirementsOfFile requirements = RequirementsOfFile.SILENT;

	public CommonProperties() {
	}

	public CommonProperties(String fileName) throws IOException {
		filePath = resolvePath(fileName);
		load();
	}

	public CommonProperties(String fileName, RequirementsOfFile isFileNotFound) throws IOException {
		this.requirements = isFileNotFound;
		filePath = resolvePath(fileName);
		load();
	}

	public void load() throws IOException {
		File file = new File(filePath);
		if (!file.exists()) {
			String message = "***CommonProperties  file not found - " + filePath;
			switch (requirements) {
				case ERROR:
					throw new RuntimeException(message);
				case PRINT:
					System.out.println(message);
					break;
			}
			return;
		}
		load2();
		isLoaded = true;
	}

	private void load2() throws FileNotFoundException, IOException {
		// List readLines = FileUtils.readLines(new File(filePath), "UTF-8");
		// for (int a = 0; a < readLines.size(); a++) {
		// String line = (String) readLines.get(a);
		// if (!line.startsWith(COMMENT)) {
		// String[] split = line.split(REGEX);
		// CProperty entryMy = null;
		// if (split.length == 2) {
		// entryMy = new CProperty(split[1].trim(), split[0].trim());
		// propertyMap.put(split[0].trim(), split[1].trim());
		// } else {
		// entryMy = new CProperty(null, line);
		// }
		// propertyList.add(entryMy);
		// }
		// }
		FileInputStream in = new FileInputStream(new File(filePath));
		InputStreamReader reader = new InputStreamReader(in, "UTF-8");
		try {
			BufferedReader bufferedReader = new BufferedReader(reader);
			String line = bufferedReader.readLine();
			while (line != null) {
				if (!line.startsWith(COMMENT)) {
					String[] split = line.split(REGEX);
					CProperty entryMy = null;
					if (split.length == 2) {
						entryMy = new CProperty(split[1].trim(), split[0].trim());
						propertyMap.put(split[0].trim(), split[1].trim());
					} else {
						entryMy = new CProperty(null, line);
					}
					propertyList.add(entryMy);
				}
				line = bufferedReader.readLine();
			}
		} finally {
			in.close();
		}
	}

	private String resolvePath(String fileName) throws IOException {
		try {
			Bundle bundle = Platform.getProduct().getDefiningBundle();// Platform.getBundle(bundleName);
			Path path = new Path(SLASH + fileName);
			URL url = FileLocator.find(bundle, path, null); //$NON-NLS-1$
			if (url != null) {
				try {
					return FileLocator.toFileURL(url).getPath();
				} catch (Exception e) {
					e.printStackTrace();
				}
			} else {
				String message = "***CommonProperties  file not found - " + fileName + " - " + bundle.getSymbolicName() + "  " + path;
				switch (requirements) {
					case ERROR:
						throw new RuntimeException(message);
					case PRINT:
						System.out.println(message);
						break;
				}
			}
		} catch (Exception e) {
		}
		return fileName;
	}

	public void save() throws FileNotFoundException, IOException {
		Writer out = new FileWriter(filePath);
		try {
			for (Entry<String, String> entry : propertyList) {
				if (entry.getValue() == null) {
					out.write(entry.getKey());
				} else {
					out.write(entry.getKey() + REGEX + entry.getValue());
				}
			}
		} finally {
			out.close();
		}
	}

	public InputStream toStream() throws IOException {
		StringBuilder builder = new StringBuilder();
		for (Entry<String, String> entry : propertyMap.entrySet()) {
			builder.append(entry.getKey());
			builder.append(REGEX);
			builder.append(entry.getValue());
			builder.append(NN);
		}
		return new ByteArrayInputStream(builder.toString().getBytes());
	}

	public String getProperty(String propName, String defaultValue) {
		String value = propertyMap.get(propName);
		if (value == null) {
			value = defaultValue;
		}
		return value;
	}

	private void setProperty(String propName, String string) {
		propertyMap.put(propName, string);
	}

	public Double getDouble(String propName) {
		return Double.valueOf(getProperty(propName, "0d"));
	}

	public Integer getInteger(String propName) {
		return Integer.valueOf(getProperty(propName, "-1"));
	}

	public Integer getInteger(String propName, String string) {
		return Integer.valueOf(getProperty(propName, string));
	}

	public Long getLong(String propName) {
		return Long.valueOf(getProperty(propName, "0L"));
	}

	public Long getLong(String propName, String string) {
		return Long.valueOf(getProperty(propName, string));
	}

	public Boolean getBoolean(String propName) {
		return Boolean.valueOf(getProperty(propName, "false"));
	}

	public String getString(String propName) {
		return getProperty(propName, "");
	}

	public String getString(String propName, String defaultValue) {
		return getProperty(propName, defaultValue);
	}

	public void setInteger(String propName, Integer value) {
		setProperty(propName, value.toString());
	}

	public void setLong(String propName, Long value) {
		setProperty(propName, value.toString());
	}

	public void setBoolean(String propName, Boolean value) {
		setProperty(propName, value.toString());
	}

	public void setString(String propName, String value) {
		setProperty(propName, value);
	}

	public String getFilePath() {
		return filePath;
	}
	public class CProperty implements Entry<String, String> {

		private String valueIn;
		private String keyIn;

		public CProperty(String valueIn, String keyIn) {
			this.valueIn = valueIn;
			this.keyIn = keyIn;
		}

		@Override
		public String getKey() {
			return keyIn;
		}

		@Override
		public String getValue() {
			return valueIn;
		}

		@Override
		public String setValue(String value) {
			return valueIn;
		}
	}

	public boolean isLoaded() {
		return isLoaded;
	}

	public List<CProperty> getEntryList() {
		return propertyList;
	}

	public Map<String, String> getPropertyMap() {
		return propertyMap;
	}
	public enum RequirementsOfFile {
		SILENT, PRINT, ERROR
	}
}
